#include "py_base.hpp"
#include <compile.h>
#include <dictobject.h>
#include <import.h>
#include <moduleobject.h>
#include <object.h>
#include <pybind11/gil.h>
#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
#include <utils/log.hpp>



PyScriptBase::~PyScriptBase()
{
    py::gil_scoped_acquire gil;
    auto name = PyModule_GetName(m_.ptr());
    PyDict_DelItemString(PyImport_GetModuleDict(), name);
}

bool PyScriptBase::compile_module_code(const char *code, const char *module_name)
{
    if (code && module_name) {
        py::gil_scoped_acquire gil;
        if (auto py_code = Py_CompileString(code, "<script>", Py_file_input)) {
            if (auto py_m = PyImport_ExecCodeModule(module_name, py_code))
            {
                m_ = py::reinterpret_steal<py::module>(py_m);
                Py_DecRef(py_m);
            }
            Py_DecRef(py_code);
        } else {
            PyObject* type, * value, * trace;
            PyErr_Fetch(&type, &value, &trace);
            if (type) {
                L_ERROR("load error, type %s", PyExceptionClass_Name(type));
            }
            if (value) {
                PyObject* str = PyObject_Str(value);
                if (str)
                {
                    const char* msg = PyUnicode_AsUTF8(str);
                    L_ERROR("could not load %s, error msg: %s", module_name, msg);
                    Py_XDECREF(str);
                }
            }
            for (auto tp = (PyTracebackObject*)trace; tp; tp = tp->tb_next) {
                auto code = PyFrame_GetCode(tp->tb_frame);
                auto line = PyUnicode_FromFormat("  File: \"%U\", line %d in %U",
                    code->co_filename,
                    tp->tb_lineno,
                    code->co_name
                    );
                Py_XDECREF(code);
            }
            Py_XDECREF(trace);
            Py_XDECREF(value);
            Py_XDECREF(type);

            PyErr_Clear();
            return false;
        }
    }
    return !m_.attr("main").is_none();
}
